package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Sets;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.UserDto;
import com.zzyl.entity.User;
import com.zzyl.entity.UserRole;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeptMapper;
import com.zzyl.mapper.RoleMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.mapper.UserRoleMapper;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.service.UserService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.vo.RoleVo;
import com.zzyl.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description UserServiceImpl
 * @Author Lwj
 * @Date 2024-09-03-15:31
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private SecurityConfigProperties securityConfigProperties;


    /**
     * 用户分页
     *
     * @param userDto
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public PageResponse<UserVo> getUserPage(UserDto userDto, Integer pageNum, Integer pageSize) {
        if (!EmptyUtil.isNullOrEmpty(userDto.getDeptNo())) {
            //截取部门编号  100001  dept_no like '100001%'
            userDto.setDeptNo(NoProcessing.processString(userDto.getDeptNo()));
        }
        PageHelper.startPage(pageNum, pageSize);
        Page<List<User>> page = userMapper.selectPage(userDto);
        PageResponse<UserVo> pageResponse = PageResponse.of(page, UserVo.class);
        if (!EmptyUtil.isNullOrEmpty(pageResponse.getRecords())) {
            List<Long> userIds = pageResponse.getRecords().stream().map(UserVo::getId).collect(Collectors.toList());
            //查询对应角色page = {Page@14103}  size = 9
            List<RoleVo> roleVoList = roleMapper.findRoleVoListInUserId(userIds);
            //装配数据
            pageResponse.getRecords().forEach(n -> {
                //装配角色
                Set<String> roleVoIds = Sets.newHashSet();
                Set<String> roleVoLabels = Sets.newHashSet();
                roleVoList.forEach(r -> {
                    if (String.valueOf(n.getId()).equals(r.getUserId())) {
                        roleVoIds.add(String.valueOf(r.getId()));
                        roleVoLabels.add(r.getRoleName());
                    }
                });
                n.setRoleLabels(roleVoLabels);
                n.setRoleVoIds(roleVoIds);
            });
        }
        return pageResponse;
    }

    /**
     * 用户添加
     *
     * @param userDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertUser(UserDto userDto) {
        //类型转换
        User user = BeanUtil.toBean(userDto, User.class);
        user.setUsername(user.getEmail());
        user.setNickName(user.getRealName());
        user.setDataState(SuperConstant.DATA_STATE_0);
        //设置密码并需要加密
        String password = BCrypt.hashpw(securityConfigProperties.getDefaulePassword(), BCrypt.gensalt());
        user.setPassword(password);
        int flag = userMapper.insertSelective(user);
        if (flag == 0) {
            throw new RuntimeException("保存用户信息出错");
        }
        //添加角色到userRoles中间表
        Set<String> roleVoIds = userDto.getRoleVoIds();
        ArrayList<UserRole> userRoles = new ArrayList<>();
        roleVoIds.forEach(r -> {
            UserRole userRole = UserRole.builder()
                    .userId(user.getId())
                    .roleId(Long.valueOf(r))
                    .dataState(SuperConstant.DATA_STATE_0)
                    .build();
            userRoles.add(userRole);
        });
        flag = userRoleMapper.batchInsert(userRoles);
        if (flag == 0) {
            throw new RuntimeException("保存用户角色中间表出错");
        }
        /*BeanUtil.toBean(user, UserVo.class);*/
        return true;
    }

    /**
     * 判断是否是最底层部门
     *
     * @return
     */
    private boolean isLowestDept(String deptNo) {
        int count = deptMapper.isLowestDept(deptNo);
        if (count > 0) {
            return true;
        }
        return false;
    }

    /**
     * 用户修改
     *
     * @param userDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUser(UserDto userDto) {
        //根据部门编号查询，是否是最底层的部门，如果不是，不允许添加用户
        if (isLowestDept(userDto.getDeptNo())) {
            throw new BaseException(BasicEnum.USER_LOCATED_BOTTOMED_DEPT);
        }
        //转换为user实体类
        User user = BeanUtil.toBean(userDto, User.class);
        //直接去修改sys_user的数据
        userMapper.updateByPrimaryKeySelective(user);
        //判断user有没有关联的角色
        //拿到user的roleVoIds的集合判断是否为空
        Set<String> roleVoIds = userDto.getRoleVoIds();
        if (ObjectUtil.isNotEmpty(roleVoIds)) {
            //roleVoIds不为空，说明user的角色是需要更改的
            //先删除sys_user_role中间表的角色数据
            userRoleMapper.deleteByUserId(user.getId());

            //判断roleVoIds是否要改为空
            if (!userDto.getRoleVoIds().isEmpty()) {
                //不是要改为空
                //创建有个新数据用来存放要修改的角色信息
                List<UserRole> userResourceList = new ArrayList<>();
                for (String roleVoId : userDto.getRoleVoIds()) {
                    //把每个roleVoId封装为一个UserRole
                    UserRole userRole = UserRole.builder()
                            .roleId(Long.valueOf(roleVoId))
                            .userId(userDto.getId())
                            .dataState(SuperConstant.DATA_STATE_0).build();
                    //封装完成之后添加到roleResourceList里面
                    userResourceList.add(userRole);
                }
                //插入中间表数据
                userRoleMapper.batchInsert(userResourceList);
            }
        }
        return true;
    }

    /**
     * 删除用户
     *
     * @param userId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUser(Long userId) {
        // 删除用户与角色关联
        userRoleMapper.deleteUserRoleByUserId(userId);
        //删除用户与岗位关联
        userMapper.deleteByPrimaryKey(userId);
    }

    /**
     * 启用或禁用用户
     *
     * @param id
     * @param status
     */
    @Override
    public void setStatus(Long id, String status) {
        //判断用户是否存在
        User user = userMapper.selectByPrimaryKey(Long.valueOf(id));
        if (user == null) {
            throw new BaseException(BasicEnum.USER_EMPTY_EXCEPTION);
        }
        //用户存在直接禁用
        user.setDataState(status);
        userMapper.updateByPrimaryKeySelective(user);
    }

    /**
     * 用户列表
     *
     * @param userDto
     * @return
     */
    @Override
    public UserVo getUserList(UserDto userDto) {
        //类型转换
        User user = BeanUtil.toBean(userDto, User.class);
        UserVo userVo = userMapper.selectUserList(user);
        return userVo;
    }

    /**
     * 密码重置
     *
     * @param userId
     * @return
     */
    @Override
    public Boolean reSetPassword(String userId) {
        String password = BCrypt.hashpw(securityConfigProperties.getDefaulePassword(), BCrypt.gensalt());
        //根据传入的userId来查询对应的用户
        User user = userMapper.selectByPrimaryKey(Long.valueOf(userId));
        //把重置的密码封装给用户
        user.setPassword(password);
        //更新数据库
        userMapper.updateByPrimaryKeySelective(user);
        return true;
    }

    /**
     * 当前用户
     *
     * @return
     */
    /*@Override
    public UserVo CurrentUser(UserDto userDto) {

        UserVo userVo = userMapper.selectCurrentUser(userDto.getId());
        return userVo;
    }*/
}
